﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Universum.Infrastructure.Configuration;
using Lucene.Net.Documents;
using Universum.Infrastructure.Utils;
using Universum.Model.Domain.Blogs;
using Lucene.Net.Search;
using Universum.Infrastructure.Persistence;

namespace Universum.Model.Services.Indexing
{
	public class BlogArticleIndexingServiceImpl : IBlogArticleIndexingService
	{
		LuceneIndexBuilder _IndexBuilder = null;
		LuceneSearchIndex _IndexSearch = null;
		IRepository _Repository = null;
		public BlogArticleIndexingServiceImpl(IRepository repository)
		{
			_Repository = repository;
			//_IndexBuilder = new LuceneIndexBuilder(
			//    ConstantIdentifiers.LUCENE_INDEXING_FOLDER_BLOG,
			//    false);
			//_IndexSearch = new LuceneSearchIndex(
			//    ConstantIdentifiers.LUCENE_INDEXING_FOLDER_BLOG);
		}


		private void StartSearcher()
		{
			_IndexSearch = new LuceneSearchIndex(
						 ConstantIdentifiers.LUCENE_INDEXING_FOLDER_BLOG);
		}

		private void StartBuilder()
		{
			_IndexBuilder = new LuceneIndexBuilder(
						 ConstantIdentifiers.LUCENE_INDEXING_FOLDER_BLOG,
						 false);
		}

		private void CloseBuilder()
		{
			_IndexBuilder.Dispose();
			_IndexBuilder = null;
		}
		private void CloseSearcher()
		{
			_IndexSearch.Dispose();
			_IndexSearch = null; 
		}

		static readonly object lock_object = new object();

		#region IIndexingServiceBase<BlogArticle> Members

		public void Add(Universum.Model.Domain.Blogs.BlogArticle entity)
		{
			lock (lock_object)
			{
				StartBuilder();
				_IndexBuilder.AddDocument(GetDocument(entity));
				CloseBuilder();
			}

		}

		private Lucene.Net.Documents.Document GetDocument(Universum.Model.Domain.Blogs.BlogArticle entity)
		{
			Document document = new Document();
			document.Add( // ID
				new Field(
MemberUtil<BlogArticle>.MemberName(it => it.ID),
					entity.ID.ToString(),
					Field.Store.YES,
					Field.Index.UN_TOKENIZED)
				);
			document.Add( // slug
				new Field(
MemberUtil<BlogArticle>.MemberName(it => it.Slug),
					entity.Slug,
					Field.Store.YES,
					Field.Index.UN_TOKENIZED)
				);
			document.Add( // title
				new Field(
MemberUtil<BlogArticle>.MemberName(it => it.Title),
					entity.Title,
					Field.Store.YES,
					Field.Index.TOKENIZED,
					Field.TermVector.YES)
				);
			document.Add( // text
				new Field(
MemberUtil<BlogArticle>.MemberName(it => it.Text),
					entity.Text,
					Field.Store.YES,
					Field.Index.TOKENIZED,
					Field.TermVector.YES)
				);
			document.Add( // Created
				new Field(
MemberUtil<BlogArticle>.MemberName(it => it.Created),
DateTools.DateToString(entity.Created, DateTools.Resolution.DAY),
					Field.Store.YES,
					Field.Index.NO)
				);
			document.Add( // Publish
				new Field(
MemberUtil<BlogArticle>.MemberName(it => it.Publish),
DateTools.DateToString(entity.Publish, DateTools.Resolution.DAY),
					Field.Store.YES,
					Field.Index.NO)
				);

			return document;
		}

		public void Remove(Universum.Model.Domain.Blogs.BlogArticle entity)
		{

			lock (lock_object)
			{
				StartBuilder();
				_IndexBuilder.RemoveDocument(GetDocument(entity));
				CloseBuilder();
			}
		}

		public void Update(Universum.Model.Domain.Blogs.BlogArticle entity)
		{
			lock (lock_object)
			{
				StartBuilder();
				_IndexBuilder.UpdateDocument(GetDocument(entity));
				CloseBuilder();
			}
		}

		public List<Universum.Model.Domain.Blogs.BlogArticle> Find(string query, int pageIndex, int pageSize)
		{
			var resultList = new List<BlogArticle>();
			Hits hits;


			lock (lock_object)
			{
				StartSearcher();

				hits = _IndexSearch.Find(query, null);

				CloseSearcher();
			}
			if (hits != null && hits.Length() > 0)
			{
				int start = pageIndex * pageSize;
				int end = (pageIndex + 1) * pageSize;
				if (hits.Length() <= end)
				{
					end = hits.Length();
				}

				for (int index = pageIndex * pageSize;
					index < end;
					index++)
				{
					var result = _Repository.Load<BlogArticle>(
						new Guid(
						hits.Doc(index).Get(MemberUtil<BlogArticle>.MemberName(it => it.ID)))
						);
					// it was probably removed from the database
					if (result == null)
					{
						lock (lock_object)
						{
							StartBuilder();
							_IndexBuilder.RemoveDocument(hits.Doc(index));
							CloseBuilder();
						}
					}
					resultList.Add(result);
				}
			}
			return resultList;
		}

		#endregion

		#region IBlogArticleIndexingService Members

		public void ReBuildAll()
		{
			lock (lock_object)
			{
				if (System.IO.Directory.Exists(
				ConstantIdentifiers.LUCENE_INDEXING_FOLDER_BLOG))
					System.IO.Directory.Delete(
						ConstantIdentifiers.LUCENE_INDEXING_FOLDER_TEACHER_ARTICLE, true);
				var allArticles = _Repository.Query<BlogArticle>();
				_IndexBuilder = new LuceneIndexBuilder(
					ConstantIdentifiers.LUCENE_INDEXING_FOLDER_TEACHER_ARTICLE,
					true);
				allArticles.ToList().ForEach(it =>
					_IndexBuilder.AddDocument(GetDocument(it)));
				_IndexBuilder.Dispose();
			}

		}

		#endregion
	}
}
